﻿using AutoMapper;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

namespace protobufConvertor
{

    public static class Extensions
    {

        public static IServiceCollection UseAutoMapper(this IServiceCollection services)
        {
            var config = new MapperConfiguration(cfg =>
            {


            });
            var mapper = config.CreateMapper();

            var Assemblylist = Assembly
               .GetEntryAssembly()//获取默认程序集
               .GetReferencedAssemblies()//获取所有引用程序集
               .Select(Assembly.Load);
            services.AddAutoMapper(cfg =>
            {
                cfg.CreateMap<Timestamp, DateTime>().ConvertUsing(new ProtoTimeToCSharpConverter());
                cfg.CreateMap<DateTime, Timestamp>().ConvertUsing(new CSharpToProtoTimeConverter());
                //var profiles = AppConfig.Profiles;
                //if (profiles.Any())
                //{
                //    foreach (var profile in profiles)
                //    {
                //        //logger.LogDebug($"解析到{profile.GetType().FullName}映射关系");
                //        cfg.AddProfile(profile);
                //    }
                //}
            }, AppConfig.GetReferenceAssembly());
            return services;
        }
    }

    public class AppConfig
    {

        public static IEnumerable<Profile> Profiles
        {
            get
            {
                var profiles = new List<Profile>();
                var referenceAssemblies = GetReferenceAssembly();
                foreach (var assembly in referenceAssemblies)
                {
                    var profileTypes = assembly.DefinedTypes.Select(p => p.AsType()).Where(p => typeof(Profile).IsAssignableFrom(p) && !p.IsAbstract).ToList();
                    if (profileTypes.Any())
                    {
                        foreach (var profileType in profileTypes)
                        {
                            try
                            {
                                var profile = Activator.CreateInstance(profileType) as Profile;
                                profiles.Add(profile);
                            }
                            catch (Exception e)
                            {
                                //if (logger.IsEnabled(LogLevel.Warning))
                                //    logger.LogWarning($"构建profile失败,profile类型为{profileType.FullName}");
                            }

                        }
                    }
                }
                return profiles;
            }
        }

        public static IEnumerable<Assembly> Assemblies
        {
            get
            {
                var referenceAssemblies = GetReferenceAssembly();
                return referenceAssemblies;
            }
        }
        private static List<Assembly> _referenceAssembly = new List<Assembly>();
        public static List<Assembly> GetReferenceAssembly(params string[] virtualPaths)
        {
            var refAssemblies = new List<Assembly>();//Assembly 通过此类能够载入操纵一个程序集，并获取程序集内部信息
            var rootPath = AppContext.BaseDirectory;
            var existsPath = virtualPaths.Any();//判断是否有数据

            var result = _referenceAssembly;
            if (!result.Any() || existsPath)
            {
                var paths = virtualPaths.Select(m => Path.Combine(rootPath, m)).ToList();
                if (!existsPath) paths.Add(rootPath);
                paths.ForEach(path =>
                {
                    var assemblyFiles = GetAllAssemblyFiles(path);

                    foreach (var referencedAssemblyFile in assemblyFiles)
                    {
                        var referencedAssembly = Assembly.LoadFrom(referencedAssemblyFile);
                        if (!_referenceAssembly.Contains(referencedAssembly))
                            _referenceAssembly.Add(referencedAssembly);
                        refAssemblies.Add(referencedAssembly);
                    }
                    result = existsPath ? refAssemblies : _referenceAssembly;
                });
            }
            return result;
        }

        private static List<string> GetAllAssemblyFiles(string parentDir)
        {
            var pattern = "^Microsoft.\\w*|^System.\\w*";
            Regex notRelatedRegex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);

            return Directory.GetFiles(parentDir, "*.dll").Select(Path.GetFullPath).Where(
                    a => !notRelatedRegex.IsMatch(a)).ToList();

        }

    }



    public class CSharpToProtoTimeConverter : ITypeConverter<DateTime, Timestamp>
    {

        public Timestamp Convert(DateTime source, Timestamp destination, ResolutionContext context)
        {
            var inputDate = source;
            var proTime = inputDate.ToUniversalTime().ToTimestamp();
            return proTime;

        }
    }

    public class ProtoTimeToCSharpConverter : ITypeConverter<Timestamp, DateTime>
    {
        public DateTime Convert(Timestamp source, DateTime destination, ResolutionContext context)
        {
            var inputTimestamp = source;
            var csharTime = inputTimestamp.ToDateTime().ToLocalTime();
            return csharTime;
        }
    }
}
